package myicesscheduler.web;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import myicesscheduler.hibernate.HibernateUtilPublic;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MyFolderUtil
{
   public static String uploadFolder_folderPropertyName = "myicesscheduler.upload.folder";
   public static final MyFolderInterface uploadFolder = new MyFolderCustomPath( "upload",
         uploadFolder_folderPropertyName, LogFactory.getLog( MyFolderUtil.class ), false );

   public static String backupFolder_folderPropertyName = "myicesscheduler.backup.folder";
   public static final MyFolderInterface backupFolder = new MyFolderCustomPath( "backup",
         backupFolder_folderPropertyName, LogFactory.getLog( MyFolderUtil.class ), true );

   public static String restoreFolder_folderPropertyName = "myicesscheduler.restore.folder";
   public static final MyFolderInterface restoreFolder = new MyFolderCustomPath( "restore",
         restoreFolder_folderPropertyName, LogFactory.getLog( MyFolderUtil.class ), true );

   public static final MyFolderInterface databaseFolder = new DatabaseFolder();

   private static abstract class MyFolderBase implements MyFolderInterface
   {
      protected final Log logger;
      private boolean bRequireAdminPermission;

      public MyFolderBase( Log logger, boolean bRequireAdminPermission )
      {
         this.logger = logger;
      }

      public String getAbsolutePathOfFile( String filename )
      {
         final String absoluteFolder = getAbsolutePath();
         return MyFileUtil.getCanonicalPath( absoluteFolder, filename );
      }

      public String[] getAbsolutePathOfFiles()
      {
         return getAbsolutePathOfFiles( null );
      }

      public String[] getAbsolutePathOfFiles( FilenameFilter filter )
      {
         final String absoluteFolder = getAbsolutePath();
         final List< String > rst = getAbsolutePathOfFiles( absoluteFolder, filter );
         return rst.toArray( new String[ rst.size() ] );
      }

      private List< String > getAbsolutePathOfFiles( String baseFolder, FilenameFilter filter )
      {
         final List< String > rst = new LinkedList< String >();

         final File folder = new File( baseFolder );
         final String[] childs = ( ( null == filter ) ? folder.list() : folder.list( filter ) );
         if( null == childs ) return rst;

         for( final String child : childs )
         {
            final String path = MyFileUtil.getPath( baseFolder, child );
            final File pathFH = new File( path );
            if( pathFH.isFile() ) rst.add( path );
            if( pathFH.isDirectory() ) rst.addAll( getAbsolutePathOfFiles( path, filter ) );
         }
         return rst;
      }

      public boolean isSameFile( String pathname, byte[] data )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return false;
         return MyFileUtil.isSameFile( MyFileUtil.getPath( uploadFolder, pathname ), data );
      }

      public boolean isThereFile( String pathname )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return false;
         return MyFileUtil.isThereFile( MyFileUtil.getPath( uploadFolder, pathname ) );
      }

      public boolean isThereFolder( String subFolderName )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return false;
         return MyFileUtil.isThereFolder( MyFileUtil.getPath( uploadFolder, subFolderName ) );
      }

      public boolean createFolder( String subfoldername )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return false;
         return MyFileUtil.createFolder( MyFileUtil.getPath( uploadFolder, subfoldername ) );
      }

      public boolean createFolders( String[] subfoldernames )
      {
         for( final String subfoldername : subfoldernames )
         {
            final boolean bRst = createFolder( subfoldername );
            if( bRst ) continue;

            logger.warn( "createFolders failed: " + subfoldername );
            return false;
         }
         return true;
      }

      public boolean removeFolderIfEmpty( String subfoldername )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return false;
         return MyFileUtil.removeFolderIfEmpty( MyFileUtil.getPath( uploadFolder, subfoldername ) );
      }

      public boolean removeFile( String pathname )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return false;
         return MyFileUtil.removeFile( MyFileUtil.getPath( uploadFolder, pathname ) );
      }

      public boolean storeFile( String pathname, byte[] bytes )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return false;
         createFolders( MyFileUtil.getFullPathFoldernames( pathname ) );
         return MyFileUtil.storeFile( MyFileUtil.getPath( uploadFolder, pathname ), bytes );
      }

      public byte[] readFile( String pathname )
      {
         final String uploadFolder = getAbsolutePath();
         if( null == uploadFolder ) return null;
         return MyFileUtil.readFile( MyFileUtil.getPath( uploadFolder, pathname ) );
      }

      public boolean isRequireAdminPermission()
      {
         return bRequireAdminPermission;
      }
   }

   private static class MyFolderCustomPath extends MyFolderBase
   {
      public final String foldernameDefault;
      public final String folderPropertyName;

      public MyFolderCustomPath( String foldernameDefault, String folderPropertyName, Log logger,
            boolean bRequireAdminPermission )
      {
         super( logger, bRequireAdminPermission );
         this.foldernameDefault = foldernameDefault;
         this.folderPropertyName = folderPropertyName;
      }

      public String getAbsolutePath()
      {
         final String folderProperty = System.getProperty( folderPropertyName );
         if( null != folderProperty )
         {
            final File folder = new File( folderProperty );
            String absolutePath;
            try
            {
               absolutePath = folder.getCanonicalPath();
            } catch( IOException e )
            {
               e.printStackTrace();
               absolutePath = folder.getAbsolutePath();
            }

            if( !folder.exists() )
            {
               final boolean bCreateFolder = MyFileUtil.createFolder( absolutePath );
               if( false == bCreateFolder )
                  throw new RuntimeException( "Upload folder cannot be created: " + absolutePath );
            }

            if( !folder.canWrite() )
               throw new RuntimeException( "Upload folder must be writable:" + absolutePath );

            return absolutePath;
         }

         final String catalinaBase = System.getProperty( "catalina.base" );
         final String catalinaHome = System.getProperty( "catalina.home" );
         final String[] candidates = new String[] { catalinaBase, catalinaHome };

         for( final String catalinaRoot : candidates )
         {
            if( null == catalinaRoot ) continue;

            final File webapps = new File( MyFileUtil.getPath( catalinaHome, "webapps" ) );
            if( !webapps.exists() || !webapps.isDirectory() )
            {
               logger.warn( "webapps folder is not found under a folder: " + catalinaRoot );
               continue;
            }

            final File app = new File( MyFileUtil.getPath( webapps.getAbsolutePath(),
                  "myicesscheduler" ) );
            if( !app.exists() || !app.isDirectory() )
            {
               logger.warn( "webapp folder does not have the web application folder: "
                     + "myicesscheduler" );
               continue;
            }

            final File webInf = new File( MyFileUtil.getPath( app.getAbsolutePath(), "WEB-INF" ) );
            if( !webInf.exists() || !webInf.isDirectory() )
            {
               logger.error( "WEB-INF folder is not found under a folder:" + app.getAbsolutePath() );
               continue;
            }

            final File folder = new File( MyFileUtil.getPath( webInf.getAbsolutePath(),
                  foldernameDefault ) );
            String absolutePath;
            try
            {
               absolutePath = folder.getCanonicalPath();
            } catch( IOException e )
            {
               e.printStackTrace();
               absolutePath = folder.getAbsolutePath();
            }

            if( !folder.exists() )
            {
               if( !webInf.canWrite() )
               {
                  logger.warn( "Default upload folder cannot be created, "
                        + " because WEB-INF folder is not writable." );
                  continue;
               }

               final boolean bCreateFolder = MyFileUtil.createFolder( absolutePath );
               if( !bCreateFolder )
               {
                  logger.error( "An error occured on creating a folder: " + absolutePath );
                  continue;
               }
            }

            if( !folder.canWrite() )
            {
               logger.error( "Uploader folder must be writable: " + absolutePath );
               continue;
            }

            return absolutePath;
         }

         throw new RuntimeException( "A system property, " + folderPropertyName + " is not found." );
      }

   }

   private static class DatabaseFolder extends MyFolderBase
   {
      private final static Log logger = LogFactory.getLog( DatabaseFolder.class );

      public DatabaseFolder()
      {
         super( logger, true );
      }

      public String getAbsolutePath()
      {
         final String absolutePath = HibernateUtilPublic.getAbsoluteDatabaseFolder();
         logger.info( "Database absolute path: " + absolutePath );
         return absolutePath;
      }

      public boolean storeFile( String filename, byte[] bytes )
      {
         final String databaseFolder = getAbsolutePath();

         HibernateUtilPublic.shutdown();
         // TODO Auto-generated method stub
         HibernateUtilPublic.startDB();

         return false; // not yet implemented.
      }

   }
}
